package com.ziq.base.base

import android.content.Context
import android.content.pm.PackageManager
import com.ziq.base.base.hilt.ConfigModule
import com.ziq.base.common.Constant
import dagger.hilt.android.qualifiers.ApplicationContext
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ManifestParser @Inject constructor() {

    @Inject
    @ApplicationContext
    lateinit var context: Context

    fun parse(): List<ConfigModule> {
        val modules: MutableList<ConfigModule> = ArrayList()
        context.let {
            try {
                val appInfo = context.packageManager.getApplicationInfo(
                    context.packageName, PackageManager.GET_META_DATA
                )
                if (appInfo.metaData != null) {
                    for (key in appInfo.metaData.keySet()) {
                        if (Constant.MODULE_VALUE == appInfo.metaData[key]) {
                            modules.add(parseModule(key))
                        }
                    }
                }
            } catch (e: PackageManager.NameNotFoundException) {
                throw RuntimeException("Unable to find metadata to parse ConfigModule", e)
            }
        }
        return modules
    }

    companion object {
        private fun parseModule(className: String): ConfigModule {
            val clazz: Class<*> = try {
                Class.forName(className)
            } catch (e: ClassNotFoundException) {
                throw IllegalArgumentException("Unable to find ConfigModule implementation", e)
            }
            val module: Any = try {
                clazz.newInstance()
            } catch (e: InstantiationException) {
                throw RuntimeException(
                    "Unable to instantiate ConfigModule implementation for $clazz",
                    e
                )
            } catch (e: IllegalAccessException) {
                throw RuntimeException(
                    "Unable to instantiate ConfigModule implementation for $clazz",
                    e
                )
            }
            if (module !is ConfigModule) {
                throw RuntimeException("Expected instanceof ConfigModule, but found: $module")
            }
            return module
        }
    }
}